package com.SpringIoc.test_1_25_springioc_and_di;

import com.SpringIoc.test_1_25_springioc_and_di.Component.UserComponent;
import com.SpringIoc.test_1_25_springioc_and_di.Config.UserInfo;
import com.SpringIoc.test_1_25_springioc_and_di.Configuration.UserConfiguration;
import com.SpringIoc.test_1_25_springioc_and_di.Controller.UserController;
import com.SpringIoc.test_1_25_springioc_and_di.Repository.UserRepository;
import com.SpringIoc.test_1_25_springioc_and_di.Service.UserService;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;


@SpringBootApplication // 启动类
public class Test125SpringIocAndDiApplication {

    public static void main(String[] args) {
        // 这个我们称之为 Spring 上下文
        // 这是翻译过来的概念, 由 Context 翻译来的
        ApplicationContext applicationContext = SpringApplication.run(Test125SpringIocAndDiApplication.class, args);
        // 这一行命令帮我们把整个应用给启动了
        // 返回的就是容器的信息, 所以我们只需要从这里面拿就行了
        // 用 ApplicationContext 来接收
        // ApplicationContext 就是应用环境, 那这个应用指的就是 容器
        // 所以 返回的就是 Spring 的运行环境

        // Context 给我们提供了一些方法, 其中 Bean 就是, 一般看getBean
        // 一共有三个 getBean
        // 可以拿名称来取, 也可以拿类型来取
        //从 Context 中 获取 Bean
        UserController bean =  applicationContext.getBean(UserController.class);
         bean.doController();

        // 这样操作就拿到了 容器里面的东西了
        // 但是如果去掉 Controller 注解就会报错
        // 报错信息显⽰: 找不到类型是: com.example.demo.controller.UserController的bean
        // 没有找到bean 这个类型的定义

        // 从Service 获取 Bean
        // 还是通过类型拿到对象
        UserService service =  applicationContext.getBean(UserService.class);
        service.doService();
        // 接下来根据名称来获取Bean (演示这一个)
        UserService service1 = (UserService)applicationContext.getBean("userService"); // 以小驼峰的方式命名
        // 想要拿到它还需要进行类型的转换
        service1.doService();
        // 第三种方式, 根据名称和类型来去拿bean
        UserService service2 = applicationContext.getBean("userService",UserService.class);
        // 这个就不需要进行类型的转换了
        service2.doService();
        // 一般情况更多的是使用前两个
        // 这三种方式也试用其他注解类型

        // 但是 Bean 里面的 默认小驼峰命名 还有一个特殊情况
        // 就是 如果类名前两位都为大写,bean的名称为类名, 不用变
        // 之后就没有其他的特殊情况了 , 这就是 Java 的标准, Bean内部的实现方式
        // 但是也可以自己修改,就是在五大注解里面自己定义
        // 获取的时候 就要用 程序员自己定义的名字了
        // @Bean的重命名, 也是可以直接加的,里面可以命名多个名字,之后可以获取其中的一个就可以
        // @Bean("u1") 或者 @Bean("u2","uu")
        // 注意" 一个Bean 可以有多个名称, 但是一个名称只能对应一个 Bean


        // Repository 采用类名方式获取bean
        UserRepository repository =  applicationContext.getBean(UserRepository.class);
        repository.doRepository();
        // 同样注解删掉之后也不会运行成功的
        // 这几个注解都是告诉Spring 把对象存进去

        // 同样采取类名的方式获取
        UserComponent component = applicationContext.getBean(UserComponent.class);
        component.doComponent();

        // 同样采取类名的方式获取
        UserConfiguration configuration = applicationContext.getBean(UserConfiguration.class);
        configuration.doConfiguration();

        // @Bean演示
      /* UserInfo userInfo =  applicationContext.getBean(UserInfo.class);
        System.out.println(userInfo);*/
        //这样写会报错, 报的没有Bean定义
        // 我们依然需要加上五大注解的 @Configuration / @Component 来告诉 Spring 我们这个代码, 并让Spring 在里面扫描
        // 但是依然报错了
        // 这次的错误是 期望只有⼀个匹配, 结果发现了两个, UserInfo, UserInfo2
        // 从这里看出来, 在使用 @Bean 注解时, bean 的名称是 方法名
        // 接下来我们根据名称来获取bean对象

        UserInfo userInfo =  (UserInfo) applicationContext.getBean("userInfo1");
        UserInfo userInfo2 =  (UserInfo) applicationContext.getBean("userInfo2");
        System.out.println(userInfo);
        System.out.println(userInfo2);
        // 这样就运行出来了

    }

}
